#ifndef __MCS__BLOCK__HPP
#define __MCS__BLOCK__HPP

#include "Element.hpp"

class Variable;
class Program;
class FunctionFactory;

/// Groups zero or more elements into a single item.
/**
Being subclass of the Element class, the Block class organizes all elements of
the program into a tree.

Block provides child objects with variable name resolution and other vitaly
important services.

During parsing process element objects are constructed before their parent block
object, therefore post-constructor initialization is used to connect element to
its parent block.

When initializing child elements, block acts as a visitor, e.g. child elements
invoke registerVariableDeclaration(), registerBlock() and other functions to
perform extended cooperation with block specific for each Element subclass.
*/
class Block : public Element
{
public:
	Block(SourceLocation const & location);
	~Block();

	/// Appends non-initiazed \p element to the block.
	void appendElement(ptr<Element> element);
	/// @copybrief Element::concat().
	/** Overrides default behaviour - appends \p other to itself and returns this. */
	virtual ptr<Element> concat(ptr<Element> other);

	/// Initializes all children elements recursively.
	virtual void init(Block * parentBlock);
	/// Initializes block as root block of the program.
	void initAsRoot(Program * program);

	/// Visit method that registers variable declarations
	/** Invoked from VariableDeclaration::init() */
	void registerVariableDeclaration(ptr<Variable> var);
	/// Visit method that registers child block.
	/** Invoked from Block::init() */
	void registerBlock(ptr<Block> block);

	/// Provides child elements with variable name resolution service.
	/** If variable is not declared in this block, search is continued recursively
	in parent block, if any. If variable was not found returns null pointer. */
	ptr<Variable> resolveVariable(String const & name) const;
	/// Provides child elements with output stream for all text generated by the script.
	std::ostream & outputStream() const;
	/// Provides child elements with function name resolution service.
	FunctionFactory * functionFactory() const;

	/// Recursively executes all children elements in order of declaration.
	virtual void execute() const;

	/// Registers instantiated variable for cleanup when leaving block.
	/** Invoked from VariableDeclaration::execute() */
	void registerVariableForCleanup(ptr<Variable> var) const;
private:
	typedef std::map< String, ptr<Variable> > VariableMap;
	/// Complete list of the child elements.
	std::vector< ptr<Element> > elements_;
	/// List of child blocks. Used when checking variable name conflicts.
	std::vector< ptr<Block> > blocks_;
	/// Map of all variables  for fast variable name resolution.
	VariableMap varMap_;
	/// Mutable stack of instantiated variables.
	mutable std::vector< ptr<Variable> > vars_;
	/// Pointer to Program object. Passed via initAsRoot() or inherited from parent block.
	Program * program_;
	
	/// Recursively checks for variable name conflicts.
	/** @param vars Variables of the parent block. */
	void checkVariables(VariableMap const & vars);
};

#endif //__MCS__BLOCK__HPP
